﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Cms.Core.Application.Secutiry.Base;
using Cms.Core.Infrastructure.AuthHelper;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Cms.Core.Infrastructure.Extension.Caching;
using Cms.Core.Infrastructure.Extension;

namespace Cms.Core.Application.Secutiry.Token
{
    /// <summary>
    /// 
    /// </summary>
    public class OnlineTokenCache : OnlineCacheAbstract, IOnlineTokenCache
    {

        private readonly IServiceProvider _serviceProvider;
        private readonly IDistributedCache _cache;
        private readonly PermissionRequirement _permissionRequirement;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceProvider"></param>
        public OnlineTokenCache(IServiceProvider serviceProvider, IDistributedCache cache)
        {

            _serviceProvider = serviceProvider;
            _cache = cache;
            _permissionRequirement = serviceProvider.GetRequiredService<PermissionRequirement>();
        }


        public DateTime TimeSpanToDateTime(long span)
        {
            DateTime time = DateTime.MinValue;
            DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1, 0, 0, 0, 0));
            time = startTime.AddSeconds(span);
            return time;
        }

        public long GetTimeSpan(DateTime time)
        {
            DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1, 0, 0, 0, 0));
            return (long)(time - startTime).TotalSeconds;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="token"></param>
        /// <param name="expirationTime"></param>
        /// <returns></returns>
        public OnlineToken GetOrRefresh(Guid userId, string token, DateTime expirationTime)
        {
            userId.NotNull(nameof(userId));
            token.NotNullOrEmpty(nameof(token));
            expirationTime.NotNull(nameof(expirationTime));

            //DateTimeOffset dateTimeOffset = new DateTimeOffset(expirationTime);
            var options = base.SetAbsoluteExpiration(TimeSpan.FromMinutes(_permissionRequirement.RefreshCoefficients));

            var key = $"cms_onlinetoken_{token}";
            return _cache.Get<OnlineToken>(key, () =>
            {

                return _serviceProvider.ExecuteScopedWork<OnlineToken>(provider =>
                {
                    IOnlineTokenProvider onlineTokenProvider = provider.GetService<IOnlineTokenProvider>();
                    return onlineTokenProvider.Create(provider, userId, token, expirationTime).Result;
                });
            }, options);

        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="token"></param>
        /// <param name="expirationTime"></param>
        /// <returns></returns>
        public async Task<OnlineToken> GetOrRefreshAsync(Guid userId, string token, DateTime expirationTime)
        {
            userId.NotNull(nameof(userId));
            token.NotNullOrEmpty(nameof(token));
            expirationTime.NotNull(nameof(expirationTime));

            var options = base.SetSlidingExpiration(TimeSpan.FromMinutes(_permissionRequirement.RefreshCoefficients));
            var key = $"cms_onlinetoken_{token}";



            return await _cache.GetAsync<OnlineToken>(key, () =>
            {
                return _serviceProvider.ExecuteScopedWorkAsync<OnlineToken>(async provider =>
                {
                    IOnlineTokenProvider onlineTokenProvider = provider.GetService<IOnlineTokenProvider>();
                    return await onlineTokenProvider.Create(provider, userId, token, expirationTime);

                });


            }, options);

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>

        public async Task<OnlineToken> GetAsync(string token)
        {
            token.NotNullOrEmpty(nameof(token));
            var key = $"cms_onlinetoken_{token}";
            return await _cache.GetAsync<OnlineToken>(key);
        }

        /// <summary>
        /// 移除
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {
            _cache.Remove(key);
        }
    }
}
